/*
 * @Author: xiaosihan
 * @Date: 2021-06-06 12:38:04
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2021-06-07 00:45:42
 */

import * as React from 'react';
import * as THREE from 'three';
import { Mesh, MeshMaterialType, Object3DComponent, Text2D, Text3D, TextAlign, Transition } from 'xsh-react-three';
import Object3D from 'xsh-react-three/lib/Object3D/Object3D';
import { Object3DComponentProps } from 'xsh-react-three/lib/Object3D/Object3DComponent';
import { THREEMouseEvent } from 'xsh-react-three/lib/Renderer/THREEMouse';
export interface Button3DProps extends Object3DComponentProps {
    text?: string,
    textColor?: string,
    textSize?: number,
    thickness?: number,
    borderRadius?: number,
    textMaterial?: MeshMaterialType,
    material?: MeshMaterialType,
    color?: string,
    cursor?: string;//-----------------------------鼠标样式
    onMousemove?: (e: THREEMouseEvent) => void,//--鼠标滑动事件
    onMouseleave?: (e: THREEMouseEvent) => void,//-鼠标离开事件
    onMouseenter?: (e: THREEMouseEvent) => void,//-鼠标进入事件
    onMousedown?: (e: THREEMouseEvent) => void,//--鼠标按下事件
    onMouseup?: (e: THREEMouseEvent) => void,//----鼠标弹起事件
    onClick?: (e: THREEMouseEvent) => void,//------鼠标点击事件

    update?: (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, text2dObject3d: Object3D) => void;
}

interface State {
    isInit: boolean;
}

export default class Button3D extends Object3DComponent<Button3DProps, State> {
    constructor(props: Button3DProps) {
        super(props);
    }

    static defaultProps = {
        textSize: 1,
        color: "#40a9ff",
        thickness: 0.1,
        borderRadius: 0.1,
        cursor: undefined,
        textMaterial: MeshMaterialType.MeshBasicMaterial,
        material: MeshMaterialType.MeshNormalMaterial
    }

    static btnOriginGeo = new THREE.IcosahedronGeometry(0.4, 40);

    static vec3Temp = new THREE.Vector3();

    btnGeo = Button3D.btnOriginGeo.clone();

    state: State = {
        isInit: true
    }

    width = 0;

    height = 0;

    // 文字模型更新回调
    textUpdate = (renderer: THREE.WebGLRenderer, scene: THREE.Scene, camera: THREE.Camera, geometry: THREE.BufferGeometry, material: THREE.Material, text2dObject3d: Object3D) => {
        const { min, max } = text2dObject3d.geometry.boundingBox!;
        const { textSize = 1 } = this.props;
        let width = Math.max(textSize, max.x - min.x - 0.4);
        let height = Math.max(textSize, max.y - min.y - 0.4);
        Object.assign(this, { width, height });

        if (this.state.isInit) {
            this.setState({ isInit: false });
        }

        this.computerBtnGeo();
    }

    // 计算按钮模型的形状
    computerBtnGeo = () => {
        const { width, height } = this;
        let { thickness = 0.1, borderRadius = 0.1 } = this.props;

        borderRadius = Math.max(0.001, borderRadius);

        let originPosition = Button3D.btnOriginGeo.attributes.position!;
        let btnPosition = this.btnGeo.attributes.position!;

        for (let i = 0; i < originPosition.count; i++) {

            Button3D.vec3Temp.set(
                originPosition.getX(i),
                originPosition.getY(i),
                0
            );

            let length = Button3D.vec3Temp.length();
            let newLenth = length / 0.4 * borderRadius + (0.4 - borderRadius);
            Button3D.vec3Temp.setLength(newLenth);
            Button3D.vec3Temp.setZ(originPosition.getZ(i) * borderRadius / 0.4);
            // 圆角计算↑↑↑↑↑↑

            //宽度计算
            if (Button3D.vec3Temp.x > 0) {
                Button3D.vec3Temp.x += (width / 2);
            } else {
                Button3D.vec3Temp.x += (width / -2);
            }

            //高度计算
            if (Button3D.vec3Temp.y > 0) {
                Button3D.vec3Temp.y += (height / 2);
            } else {
                Button3D.vec3Temp.y += (height / -2);
            }

            //厚度计算
            if (Button3D.vec3Temp.z > 0) {
                Button3D.vec3Temp.z += (thickness / 2);
            } else {
                Button3D.vec3Temp.z += (thickness / -2);
            }

            btnPosition.setXYZ(i,
                Button3D.vec3Temp.x,
                Button3D.vec3Temp.y,
                Button3D.vec3Temp.z
            );

        }

        btnPosition.needsUpdate = true;

        this.btnGeo.computeVertexNormals();

        const { update } = this.props;

        const { renderer, scene, camera } = this.context;

        update && update(renderer, scene, camera, this.btnGeo, this.object3d.material, this.object3d);
    }

    componentDidMount() {
        this.computerBtnGeo();
    }

    componentDidUpdate() {
        this.computerBtnGeo();
    }

    componentWillUnmount() {
        this.btnGeo.dispose();
    }

    render() {
        const {
            textSize,
            text,
            thickness = 0.1,
            borderRadius = 0.1,
            textColor,
            color,
            material,
            textMaterial,
            cursor,
            onMousemove,
            onMouseleave,
            onMouseenter,
            onMousedown,
            onMouseup,
            onClick,

        } = this.props;
        const { isInit } = this.state;
        return (
            <>
                { !isInit &&
                    <Mesh
                        geometry={this.btnGeo}
                        material={material}
                        color={color}
                        cursor={cursor}
                        onMousemove={onMousemove}
                        onMouseleave={onMouseleave}
                        onMouseenter={onMouseenter}
                        onMousedown={onMousedown}
                        onMouseup={onMouseup}
                        onClick={onClick}
                    />
                }


                <Text2D
                    duration={0}
                    text={text}
                    size={textSize}
                    color={textColor}
                    material={textMaterial}
                    textAlign={TextAlign.CENTER_CENTER}
                    curveSegments={2}
                    position={{ z: (thickness / 2) + borderRadius + 0.006 }}
                    update={this.textUpdate}
                />

                <Text2D
                    duration={0}
                    text={text}
                    size={textSize}
                    material={textMaterial}
                    color={textColor}
                    textAlign={TextAlign.CENTER_CENTER}
                    curveSegments={2}
                    position={{ z: (thickness / -2) - borderRadius - 0.006 }}
                    rotation={{ y: 180 }}
                />
            </>
        );
    }
}